package tt.dz.tcp.rpc.as;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.PostConstruct;

import org.apache.avro.Protocol;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.ipc.NettyTransceiver;
import org.apache.avro.ipc.generic.GenericRequestor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

import tt.dz.entity.base.JsonCommon;
import tt.dz.tcp.rpc.as.client.constant.AppServerConstant;
import tt.dz.tcp.rpc.as.client.entity.AppChargeNotifyParam;
import tt.dz.tcp.rpc.as.client.entity.AppExceptionNotifyParam;
import tt.dz.tcp.rpc.as.client.entity.AppOrderNotifyParam;
import tt.dz.tcp.rpc.as.client.entity.AppReservationNotifyParam;
import tt.dz.tcp.rpc.as.client.entity.AppStationUpdateNotifyParam;

/**
 * 用于和App服务通信
 * @author Administrator
 *
 */
@Component
public class SystemAppServerRpcClient {
	private static Log log = LogFactory.getLog(SystemAppServerRpcClient.class);
	
	@Value(value="${appServerIp}")
	private String appServerIp;
	@Value(value="${appServerPort}")
	private int port;
	@Value(value="${appFileName}")
	private String protocolFile;
	
	private Protocol protocol;
	public SystemAppServerRpcClient() {}
	
	private static ExecutorService receiveExecutorService = Executors.newCachedThreadPool();

    @PostConstruct
	public void init(){
    	try {
    		String filePath = this.getClass().getResource(protocolFile).getPath();
			try {
				filePath = URLDecoder.decode(filePath, "UTF-8");
			} catch (UnsupportedEncodingException e1) {
				log.error("初始化App服务器客户端错误", e1);
			}
			protocol = Protocol.parse(new File(filePath));
    	} catch (IOException e) {
			log.error("初始化App服务器客户端错误", e);
		}
    }
    
    /**
     * 站点数据更新通知接口
     * @param obj
     * @return success:成功  fail:失败
     */
    public JsonCommon<String> stationUpdateNotify(AppStationUpdateNotifyParam obj) {
    	JsonCommon<String> json = new JsonCommon<String>();
    	json.setCode(AppServerConstant.RELULT_INFO_APP_SERVIER_NOTIFY_SUCCESS_CODE); // 默认成功
    	NettyTransceiver transceiver = null;
		try {
			transceiver = new NettyTransceiver(new InetSocketAddress(appServerIp, port));
			GenericRequestor requestor = new GenericRequestor(protocol, transceiver);
			GenericRecord requestData = new GenericData.Record(protocol.getMessages().get("stationUpdateNotify").getRequest());  
			//requestData.put("params", JSON.toJSONStringWithDateFormat(obj, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat));
	        Map<String, String> param = new HashMap<>();
	        param.put("provinceId", obj.getProvinceCode());
	        param.put("updateTime", obj.getUpdateTime());
			requestData.put("params", JSON.toJSONStringWithDateFormat(param, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat));

			Object result = requestor.request("stationUpdateNotify", requestData);
	        if (result != null) {
	        	if (result.toString().equals(AppServerConstant.RELULT_INFO_FAIL)) { // 返回失败
	        		json.setCode(AppServerConstant.RELULT_INFO_STATION_UPDATE_NOTIFY_FAIL_CODE);
	        		log.error("stationUpdateNotify fail!");
				}
	        	json.setMsg(result.toString());
		    }
		} catch (Exception e) {
			log.error("App服务站点数据更新通知接口报错", e);
			json.setCode(AppServerConstant.RELULT_INFO_STATION_UPDATE_NOTIFY_EXCEPTION_CODE);
			json.setMsg(AppServerConstant.RELULT_INFO_FAIL);
		} finally {
			if(transceiver != null) {
				transceiver.close();
			}
		}
		return json;
	}

	/**
	 * 预约通知接口
	 *
	 * @param obj
	 * @return success:成功  fail:失败
	 */
	public JsonCommon<String> reservationNotify(AppReservationNotifyParam obj)
	{
		JsonCommon<String> json = new JsonCommon<String>();
		json.setCode(AppServerConstant.RELULT_INFO_APP_SERVIER_NOTIFY_SUCCESS_CODE); // 默认成功
		NettyTransceiver transceiver = null;
		try
		{
			transceiver = new NettyTransceiver(new InetSocketAddress(appServerIp, port));
			GenericRequestor requestor = new GenericRequestor(protocol, transceiver);
			GenericRecord requestData = new GenericData.Record(protocol.getMessages().get("reservationNotify").getRequest());
			requestData.put("params", JSON.toJSONStringWithDateFormat(obj, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat));
			log.debug(requestData);
			Object result = requestor.request("reservationNotify", requestData);
			log.debug(result);
			if (result != null)
			{
				if (result.toString().equals(AppServerConstant.RELULT_INFO_FAIL))
				{ // 返回失败
					json.setCode(AppServerConstant.RELULT_INFO_RESERVATION_NOTIFY_FAIL_CODE);
					log.error("reservationNotify fail!");
				}
				json.setMsg(result.toString());
			}
		}
		catch (Exception e)
		{
			log.error("App服务预约通知接口报错", e);
			json.setCode(AppServerConstant.RELULT_INFO_RESERVATION_NOTIFY_EXCEPTION_CODE);
			json.setMsg(AppServerConstant.RELULT_INFO_FAIL);
		}
		finally
		{
			if (transceiver != null)
			{
				transceiver.close();
			}
		}
		return json;
	}

	/**
     * 订单通知接口
     * @param obj
     * @return success:成功  fail:失败
     */
	public JsonCommon<String> orderNotify(AppOrderNotifyParam obj)
	{
		JsonCommon<String> json = new JsonCommon<String>();
		json.setCode(AppServerConstant.RELULT_INFO_APP_SERVIER_NOTIFY_SUCCESS_CODE); // 默认成功
		NettyTransceiver transceiver = null;
		try
		{
			transceiver = new NettyTransceiver(new InetSocketAddress(appServerIp, port));
			GenericRequestor requestor = new GenericRequestor(protocol, transceiver);
			GenericRecord requestData = new GenericData.Record(protocol.getMessages().get("orderNotify").getRequest());
			requestData.put("params", JSON.toJSONStringWithDateFormat(obj, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat));
			log.info(requestData);
			Object result = requestor.request("orderNotify", requestData);
			log.info(result);
			if (result != null)
			{
				if (result.toString().equals(AppServerConstant.RELULT_INFO_FAIL))
				{ // 返回失败
					json.setCode(AppServerConstant.RELULT_INFO_ORDER_NOTIFY_FAIL_CODE);
					log.error("orderNotify fail!");
				}
				json.setMsg(result.toString());
			}
		}
		catch (Exception e)
		{
			log.error("App服务订单通知接口报错", e);
			json.setCode(AppServerConstant.RELULT_INFO_ORDER_NOTIFY_EXCEPTION_CODE);
			json.setMsg(AppServerConstant.RELULT_INFO_FAIL);
		}
		finally
		{
			if (transceiver != null)
			{
				transceiver.close();
			}
		}
		return json;
	}

	/**
     * 异常信息通知接口
     * @param obj
     * @return success:成功  fail:失败
     */
    public JsonCommon<String> exceptionNotify(AppExceptionNotifyParam obj) {
    	JsonCommon<String> json = new JsonCommon<String>();
    	json.setCode(AppServerConstant.RELULT_INFO_APP_SERVIER_NOTIFY_SUCCESS_CODE); // 默认成功
    	NettyTransceiver transceiver = null;
		try {
			transceiver = new NettyTransceiver(new InetSocketAddress(appServerIp, port));
			GenericRequestor requestor = new GenericRequestor(protocol, transceiver);
			GenericRecord requestData = new GenericData.Record(protocol.getMessages().get("exceptionNotify").getRequest());  
			requestData.put("params", JSON.toJSONStringWithDateFormat(obj, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat));
	        Object result = requestor.request("exceptionNotify", requestData);
	        if (result != null) {
	        	if (result.toString().equals(AppServerConstant.RELULT_INFO_FAIL)) { // 返回失败
	        		json.setCode(AppServerConstant.RELULT_INFO_EXCEPTION_NOTIFY_FAIL_CODE);
	        		log.error("exceptionNotify fail!");
				}
	        	json.setMsg(result.toString());
		    }
		} catch (Exception e) {
			log.error("App服务异常信息通知接口报错", e);
			json.setCode(AppServerConstant.RELULT_INFO_EXCEPTION_NOTIFY_EXCEPTION_CODE);
			json.setMsg(AppServerConstant.RELULT_INFO_FAIL);
		} finally {
			if(transceiver != null) {
				transceiver.close();
			}
		}
		return json;
	}
    
    /**
     * 充电通知接口
     * @param obj
     * @return success:成功  fail:失败
     */
    public JsonCommon<String> chargeNotify(AppChargeNotifyParam obj) {
    	log.info("Receive response message from chargeNotify");
    	JsonCommon<String> json = new JsonCommon<String>();
    	json.setCode(AppServerConstant.RELULT_INFO_APP_SERVIER_NOTIFY_SUCCESS_CODE); // 默认成功
    	
    	final AppChargeNotifyParam obj_data = obj;
		java.util.concurrent.Future<Object> future = receiveExecutorService.submit(new Callable<Object>() {

			@SuppressWarnings("unchecked")
			@Override
			public Object call() throws Exception {
				NettyTransceiver transceiver = null;
				try {
					transceiver = new NettyTransceiver(new InetSocketAddress(appServerIp, port));
					GenericRequestor requestor = new GenericRequestor(protocol, transceiver);
					GenericRecord requestData = new GenericData.Record(protocol.getMessages().get("chargeNotify").getRequest());  
					requestData.put("params", JSON.toJSONStringWithDateFormat(obj_data, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat));
			        Object result = requestor.request("chargeNotify", requestData);
			        return result;
//			        if (result != null) {
//			        	if (result.toString().equals(AppServerConstant.RELULT_INFO_FAIL)) { // 返回失败
//			        		json.setCode(AppServerConstant.RELULT_INFO_CHARGE_NOTIFY_FAIL_CODE);
//			        		log.error("chargeNotify fail!");
//						}
//			        	json.setMsg(result.toString());
//				    }
				} catch (Exception e) {
					log.error("App服务充电通知接口报错", e);
//					json.setCode(AppServerConstant.RELULT_INFO_CHARGE_NOTIFY_EXCEPTION_CODE);
//					json.setMsg(AppServerConstant.RELULT_INFO_FAIL);
				} finally {
					if(transceiver != null) {
						transceiver.close();
					}
				}
		    	return null;
			}
		});
        try {
			if (future.get() != null) {
			if (future.get().toString().equals(AppServerConstant.RELULT_INFO_FAIL)) { // 返回失败
				json.setCode(AppServerConstant.RELULT_INFO_CHARGE_NOTIFY_FAIL_CODE);
				log.error("chargeNotify fail!");
			}
			json.setMsg(future.get().toString());
			}
		} catch (InterruptedException e) {
			log.error(e.getMessage(), e);
		} catch (ExecutionException e) {
			log.error(e.getMessage(), e);
		}
		return json;
	}
    
    public static void main(String[] args) {
    	NettyTransceiver transceiver = null;
    	try{
    		String protocolFile = "appServer.json";
    		Protocol protocol;
    		/*AppStationUpdateNotifyParam obj = new AppStationUpdateNotifyParam();
//    		obj.setProvinceId("110000");
    		obj.setProvinceCode("110000");
    		obj.setUpdateTime("2016-04-18 14:32:18");
    		
    		Map<String,String> paramMap = new HashMap<String,String>();
    		paramMap.put("provinceId", "110000");
    		paramMap.put("updateTime", "2016-04-18 14:32:18");*/
    		
    		AppReservationNotifyParam obj = new AppReservationNotifyParam();
    		obj.setAction("reservation");
    		obj.setChargerId("0028300000000184");
    		obj.setStationName("1322");
    		obj.setSerialNo("1111");
    		obj.setPlugNo("00");
    		obj.setUserCard("18808002810000002069");
    		obj.setStartTime("2016-04-15 15:39:21");
    		obj.setReservationSn("0028300000000184001201604151539210001");
    		
    		/*AppOrderNotifyParam obj = new AppOrderNotifyParam();
    		obj.setUserCard("18808002810000002069");
    		obj.setOrderNo("10086");
    		obj.setMoney("2.22");*/
    		
    		/*AppExceptionNotifyParam obj = new AppExceptionNotifyParam();
    		obj.setAction("reservation");
    		obj.setChargerId("0028300000000184");
    		obj.setStationName("1322");
    		obj.setChargerSerialNo("1111");
    		obj.setUserCard("18808002810000002069");
    		obj.setReservationSn("0028300000000184001201604151539210001");
    		obj.setChargeSn("0028300000000184001201604151539210888");
    		obj.setStartTime("2016-04-15 15:39:21");
    		obj.setResponseCode("179511");*/
    		
    		/*AppChargeNotifyParam obj = new AppChargeNotifyParam();
    		obj.setAction("reservation");
    		obj.setChargeType("2");
    		obj.setStationName("1322");
    		obj.setChargerSerialNo("1111");
    		obj.setChargerId("0028300000000184");
    		obj.setPlugNo("00");
    		obj.setUserCard("18808002810000002069");
    		obj.setChargerSn("0028300000000184001201604151539213333");
    		obj.setStartTime("2016-04-15 15:39:21");*/
    		
    		String filePath = "D:\\Development Series\\Java EE Series\\Eclipse Series\\Maven\\WorkSpace\\oms\\target\\classes\\tt\\dz\\tcp\\rpc\\as\\"+protocolFile;
//    		String filePath = SystemAppServerRpcClient.class.getResource("./appServer.json").getPath();
//    		String filePath = "D:/git_repos/git_rcp_local/dz_OMS_V2.1/src/tt/dz/tcp/rpc/as/appServer.json";
    		protocol = Protocol.parse(new File(filePath));
//    		transceiver = new NettyTransceiver(new InetSocketAddress("192.168.4.185", 9511));
    		transceiver = new NettyTransceiver(new InetSocketAddress("192.168.5.209", 9511));
    		GenericRequestor requestor = new GenericRequestor(protocol, transceiver);
			GenericRecord requestData = new GenericData.Record(protocol.getMessages().get("reservationNotify").getRequest());  
			requestData.put("params", JSON.toJSONStringWithDateFormat(obj, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat));
	        Object result = requestor.request("reservationNotify", requestData);
	        
	        if (result != null) {
	        	if (result.toString().equals(AppServerConstant.RELULT_INFO_FAIL)) { // 返回失败
	        		System.err.println("fail!");
				} else {
					System.out.println("sussess!");
				}
		    }
    	} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(transceiver != null) transceiver.close();
		}
	}
}
